using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Uow;
using TenantManagementService.Tenants;
using TenantManagementService.Monitoring;

namespace TenantManagementService.Monitoring
{
    /// <summary>
    /// 监控服务实现
    /// </summary>
    public class MonitoringService : ApplicationService, IMonitoringService
    {
        private readonly IRepository<MonitoringMetric, Guid> _metricRepository;
        private readonly IRepository<MonitoringMetricValue, Guid> _metricValueRepository;
        private readonly IRepository<AlertRule, Guid> _alertRuleRepository;
        private readonly IRepository<Alert, Guid> _alertRepository;
        private readonly IRepository<Tenant, Guid> _tenantRepository;
        private readonly ILogger<MonitoringService> _logger;

        public MonitoringService(
            IRepository<MonitoringMetric, Guid> metricRepository,
            IRepository<MonitoringMetricValue, Guid> metricValueRepository,
            IRepository<AlertRule, Guid> alertRuleRepository,
            IRepository<Alert, Guid> alertRepository,
            IRepository<Tenant, Guid> tenantRepository,
            ILogger<MonitoringService> logger)
        {
            _metricRepository = metricRepository;
            _metricValueRepository = metricValueRepository;
            _alertRuleRepository = alertRuleRepository;
            _alertRepository = alertRepository;
            _tenantRepository = tenantRepository;
            _logger = logger;
        }

        public async Task RecordMetricAsync(string metricName, decimal value, Dictionary<string, string>? dimensions = null, Guid? tenantId = null)
        {
            try
            {
                var metric = await _metricRepository.FirstOrDefaultAsync(x => x.Name == metricName && x.TenantId == tenantId);

                if (metric == null)
                {
                    // 自动创建指标
                    metric = new MonitoringMetric(
                        Guid.NewGuid(),
                        metricName,
                        metricName, // 默认显示名称与名称相同
                        GetMetricTypeFromName(metricName),
                        GetMetricCategoryFromName(metricName),
                        GetMetricUnitFromName(metricName),
                        null,
                        System.Text.Json.JsonSerializer.Serialize(dimensions),
                        tenantId
                    );

                    await _metricRepository.InsertAsync(metric);
                }

                // 添加指标值
                metric.AddValue(value, DateTime.Now, dimensions);
                await _metricRepository.UpdateAsync(metric);

                // 检查告警规则
                await CheckAlertRulesForMetric(metricName, value, dimensions, tenantId);

                _logger.LogDebug("指标记录成功: {MetricName} = {Value}", metricName, value);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "记录指标失败: {MetricName} = {Value}", metricName, value);
                throw;
            }
        }

        public async Task RecordTenantMetricAsync(Guid tenantId, string metricName, decimal value, Dictionary<string, string>? dimensions = null)
        {
            await RecordMetricAsync(metricName, value, dimensions, tenantId);
        }

        public async Task RecordMetricsAsync(List<MetricRecordInput> metrics)
        {
            if (metrics == null || metrics.Count == 0)
            {
                return;
            }

            using var uow = UnitOfWorkManager.Begin();

            try
            {
                foreach (var metric in metrics)
                {
                    await RecordMetricAsync(metric.MetricName, metric.Value, metric.Dimensions, metric.TenantId);
                }

                await uow.CompleteAsync();
            }
            catch
            {
                await uow.RollbackAsync();
                throw;
            }
        }

        public async Task<decimal?> GetMetricValueAsync(string metricName, DateTime? startTime = null, DateTime? endTime = null, Dictionary<string, string>? dimensions = null, Guid? tenantId = null)
        {
            var queryable = await _metricValueRepository.GetQueryableAsync();

            queryable = queryable.Where(v => v.Metric.Name == metricName && v.TenantId == tenantId);

            if (startTime.HasValue)
            {
                queryable = queryable.Where(v => v.Timestamp >= startTime.Value);
            }

            if (endTime.HasValue)
            {
                queryable = queryable.Where(v => v.Timestamp <= endTime.Value);
            }

            // 如果没有指定时间范围，返回最新值
            if (!startTime.HasValue && !endTime.HasValue)
            {
                var latestValue = await AsyncExecuter.FirstOrDefaultAsync(queryable.OrderByDescending(v => v.Timestamp));
                return latestValue?.Value;
            }

            // 否则返回平均值
            var values = await AsyncExecuter.ToListAsync(queryable);
            return values.Count > 0 ? values.Average(v => v.Value) : null;
        }

        public async Task<List<MetricDataPoint>> GetMetricHistoryAsync(string metricName, DateTime startTime, DateTime endTime, Dictionary<string, string>? dimensions = null, Guid? tenantId = null)
        {
            var queryable = await _metricValueRepository.GetQueryableAsync();

            queryable = queryable.Where(v => v.Metric.Name == metricName && v.TenantId == tenantId)
                                  .Where(v => v.Timestamp >= startTime && v.Timestamp <= endTime)
                                  .OrderBy(v => v.Timestamp);

            var values = await AsyncExecuter.ToListAsync(queryable);

            return values.Select(v => new MetricDataPoint
            {
                Timestamp = v.Timestamp,
                Value = v.Value,
                Dimensions = v.GetDimensions()
            }).ToList();
        }

        public async Task<TenantUsageStatistics> GetTenantUsageStatisticsAsync(Guid tenantId, DateTime? startTime = null, DateTime? endTime = null)
        {
            var tenant = await _tenantRepository.GetAsync(tenantId);

            // 获取API调用次数
            var apiCallCount = await GetMetricValueAsync(MetricConstants.Tenant.ApiCallCount, startTime, endTime, null, tenantId) ?? 0;

            // 获取平均响应时间
            var avgResponseTime = await GetMetricValueAsync(MetricConstants.Tenant.ApiResponseTime, startTime, endTime, null, tenantId) ?? 0;

            // 获取API错误率
            var apiErrorRate = await GetMetricValueAsync(MetricConstants.Tenant.ApiErrorRate, startTime, endTime, null, tenantId) ?? 0;

            return new TenantUsageStatistics
            {
                TenantId = tenantId,
                TenantName = tenant.Name,
                UserCount = tenant.CurrentUserCount,
                MaxUserCount = tenant.MaxUserCount,
                UserUsagePercentage = tenant.GetUserUsagePercentage(),
                StorageUsage = tenant.CurrentStorageUsage,
                MaxStorageSize = tenant.MaxStorageSize,
                StorageUsagePercentage = tenant.GetStorageUsagePercentage(),
                ApiCallCount = (long)apiCallCount,
                AverageApiResponseTime = (double)avgResponseTime,
                ApiErrorRate = (double)apiErrorRate,
                LastAccessTime = tenant.LastAccessTime ?? tenant.CreationTime,
                Status = tenant.Status,
                SubscriptionEndTime = tenant.SubscriptionEndTime,
                DaysUntilExpiration = tenant.SubscriptionEndTime.HasValue ?
                    Math.Max(0, (int)(tenant.SubscriptionEndTime.Value - DateTime.Now).TotalDays) : 0
            };
        }

        public async Task<TenantsOverviewStatistics> GetTenantsOverviewStatisticsAsync()
        {
            var tenants = await _tenantRepository.GetListAsync();

            var now = DateTime.Now;
            var sevenDaysLater = now.AddDays(7);

            var stats = new TenantsOverviewStatistics
            {
                TotalTenants = tenants.Count,
                ActiveTenants = tenants.Count(t => t.Status == TenantStatus.Active),
                TrialTenants = tenants.Count(t => t.Status == TenantStatus.Trial),
                SuspendedTenants = tenants.Count(t => t.Status == TenantStatus.Suspended),
                ExpiredTenants = tenants.Count(t => t.IsExpired()),
                ExpireSoonTenants = tenants.Count(t => t.SubscriptionEndTime.HasValue &&
                    t.SubscriptionEndTime.Value <= sevenDaysLater &&
                    t.SubscriptionEndTime.Value > now),
                OverUserLimitTenants = tenants.Count(t => t.IsUserLimitExceeded()),
                OverStorageLimitTenants = tenants.Count(t => t.IsStorageLimitExceeded()),
                StatisticsTime = now
            };

            // 计算总体API统计
            var totalApiCalls = await GetMetricValueAsync(MetricConstants.Tenant.ApiCallCount);
            stats.TotalApiCalls = (long)(totalApiCalls ?? 0);

            var avgResponseTime = await GetMetricValueAsync(MetricConstants.Tenant.ApiResponseTime);
            stats.AverageApiResponseTime = (double)(avgResponseTime ?? 0);

            var errorRate = await GetMetricValueAsync(MetricConstants.Tenant.ApiErrorRate);
            stats.OverallApiErrorRate = (double)(errorRate ?? 0);

            return stats;
        }

        public async Task<List<TenantResourceUsage>> GetTenantResourceUsageAsync(List<Guid>? tenantIds = null)
        {
            var queryable = await _tenantRepository.GetQueryableAsync();

            if (tenantIds != null && tenantIds.Any())
            {
                queryable = queryable.Where(t => tenantIds.Contains(t.Id));
            }

            var tenants = await AsyncExecuter.ToListAsync(queryable);

            return tenants.Select(tenant => new TenantResourceUsage
            {
                TenantId = tenant.Id,
                TenantName = tenant.Name,
                Status = tenant.Status,
                UserUsage = new ResourceUsage
                {
                    Current = tenant.CurrentUserCount,
                    Max = tenant.MaxUserCount,
                    Percentage = tenant.GetUserUsagePercentage(),
                    IsExceeded = tenant.IsUserLimitExceeded(),
                    IsWarning = tenant.GetUserUsagePercentage() >= 80,
                    IsCritical = tenant.GetUserUsagePercentage() >= 95
                },
                StorageUsage = new ResourceUsage
                {
                    Current = tenant.CurrentStorageUsage,
                    Max = tenant.MaxStorageSize,
                    Percentage = tenant.GetStorageUsagePercentage(),
                    IsExceeded = tenant.IsStorageLimitExceeded(),
                    IsWarning = tenant.GetStorageUsagePercentage() >= 80,
                    IsCritical = tenant.GetStorageUsagePercentage() >= 95
                },
                ApiUsage = new ResourceUsage
                {
                    Current = 0, // 需要从监控指标获取
                    Max = 0,
                    Percentage = 0,
                    IsExceeded = false,
                    IsWarning = false,
                    IsCritical = false
                },
                LastUpdated = DateTime.Now
            }).ToList();
        }

        public async Task CheckAlertRulesAsync()
        {
            var activeRules = await _alertRuleRepository.GetListAsync(r => r.IsEnabled);

            foreach (var rule in activeRules)
            {
                await CheckAlertRuleAsync(rule);
            }
        }

        public async Task<AlertRuleDto> CreateAlertRuleAsync(CreateAlertRuleInput input)
        {
            var rule = new AlertRule(
                Guid.NewGuid(),
                input.Name,
                input.DisplayName,
                input.MetricName,
                input.Level,
                input.Operator,
                input.Threshold,
                input.Description,
                input.Duration,
                input.EvaluationInterval,
                input.LabelFilters != null ? System.Text.Json.JsonSerializer.Serialize(input.LabelFilters) : null,
                input.NotificationChannels != null ? System.Text.Json.JsonSerializer.Serialize(input.NotificationChannels) : null,
                input.Expression,
                CurrentTenant.Id
            );

            await _alertRuleRepository.InsertAsync(rule);

            return ObjectMapper.Map<AlertRule, AlertRuleDto>(rule);
        }

        public async Task<AlertRuleDto> UpdateAlertRuleAsync(Guid id, UpdateAlertRuleInput input)
        {
            var rule = await _alertRuleRepository.GetAsync(id);

            rule.UpdateBasicInfo(input.DisplayName, input.Description)
                 .UpdateThreshold(input.Operator, input.Threshold, input.Duration)
                 .UpdateEvaluation(input.EvaluationInterval)
                 .UpdateStatus(input.IsEnabled);

            if (input.LabelFilters != null)
            {
                rule.LabelFilters = System.Text.Json.JsonSerializer.Serialize(input.LabelFilters);
            }

            if (input.NotificationChannels != null)
            {
                rule.NotificationChannels = System.Text.Json.JsonSerializer.Serialize(input.NotificationChannels);
            }

            await _alertRuleRepository.UpdateAsync(rule);

            return ObjectMapper.Map<AlertRule, AlertRuleDto>(rule);
        }

        public async Task DeleteAlertRuleAsync(Guid id)
        {
            await _alertRuleRepository.DeleteAsync(id);
        }

        public async Task<PagedResultDto<AlertRuleDto>> GetAlertRulesAsync(GetAlertRulesInput input)
        {
            var queryable = await _alertRuleRepository.GetQueryableAsync();

            queryable = queryable.WhereIf(!input.Filter.IsNullOrWhiteSpace(), x =>
                            x.Name.Contains(input.Filter) || x.DisplayName.Contains(input.Filter))
                        .WhereIf(input.Level.HasValue, x => x.Level == input.Level.Value)
                        .WhereIf(input.IsEnabled.HasValue, x => x.IsEnabled == input.IsEnabled.Value)
                        .WhereIf(!input.MetricName.IsNullOrWhiteSpace(), x => x.MetricName == input.MetricName);

            var totalCount = await AsyncExecuter.CountAsync(queryable);
            var items = await AsyncExecuter.ToListAsync(
                queryable.OrderBy(input.Sorting ?? "Name")
                    .PageBy(input.SkipCount, input.MaxResultCount)
            );

            return new PagedResultDto<AlertRuleDto>(
                totalCount,
                ObjectMapper.Map<List<AlertRule>, List<AlertRuleDto>>(items)
            );
        }

        public async Task<PagedResultDto<AlertDto>> GetActiveAlertsAsync(GetActiveAlertsInput input)
        {
            var queryable = await _alertRepository.GetQueryableAsync();

            queryable = queryable.WhereIf(!input.Filter.IsNullOrWhiteSpace(), x =>
                            x.Title.Contains(input.Filter) || x.Message.Contains(input.Filter))
                        .WhereIf(input.Level.HasValue, x => x.Level == input.Level.Value)
                        .WhereIf(input.TenantId.HasValue, x => x.TenantId == input.TenantId.Value)
                        .WhereIf(input.Status.HasValue, x => x.Status == input.Status.Value)
                        .Where(x => x.Status != AlertStatus.Resolved); // 默认只显示未解决的告警

            var totalCount = await AsyncExecuter.CountAsync(queryable);
            var items = await AsyncExecuter.ToListAsync(
                queryable.OrderByDescending(x => x.StartTime)
                    .PageBy(input.SkipCount, input.MaxResultCount)
            );

            return new PagedResultDto<AlertDto>(
                totalCount,
                ObjectMapper.Map<List<Alert>, List<AlertDto>>(items)
            );
        }

        public async Task<AlertDto> HandleAlertAsync(Guid id, HandleAlertInput input)
        {
            var alert = await _alertRepository.GetAsync(id);

            alert.Handle(input.Assignee, input.Note);

            await _alertRepository.UpdateAsync(alert);

            return ObjectMapper.Map<Alert, AlertDto>(alert);
        }

        public async Task<AlertDto> IgnoreAlertAsync(Guid id, string reason)
        {
            var alert = await _alertRepository.GetAsync(id);

            alert.Ignore(reason);

            await _alertRepository.UpdateAsync(alert);

            return ObjectMapper.Map<Alert, AlertDto>(alert);
        }

        public async Task<AlertStatistics> GetAlertStatisticsAsync(DateTime? startTime = null, DateTime? endTime = null, Guid? tenantId = null)
        {
            var queryable = await _alertRepository.GetQueryableAsync();

            if (startTime.HasValue)
            {
                queryable = queryable.Where(a => a.StartTime >= startTime.Value);
            }

            if (endTime.HasValue)
            {
                queryable = queryable.Where(a => a.StartTime <= endTime.Value);
            }

            if (tenantId.HasValue)
            {
                queryable = queryable.Where(a => a.TenantId == tenantId.Value);
            }

            var alerts = await AsyncExecuter.ToListAsync(queryable);

            return new AlertStatistics
            {
                TotalAlerts = alerts.Count,
                ActiveAlerts = alerts.Count(a => a.Status == AlertStatus.Active),
                ResolvedAlerts = alerts.Count(a => a.Status == AlertStatus.Resolved),
                IgnoredAlerts = alerts.Count(a => a.Status == AlertStatus.Ignored),
                CriticalAlerts = alerts.Count(a => a.Level == AlertLevel.Critical),
                WarningAlerts = alerts.Count(a => a.Level == AlertLevel.Warning),
                InfoAlerts = alerts.Count(a => a.Level == AlertLevel.Info),
                EmergencyAlerts = alerts.Count(a => a.Level == AlertLevel.Emergency),
                AverageResolutionTime = alerts.Where(a => a.Status == AlertStatus.Resolved && a.EndTime.HasValue)
                    .Select(a => (a.EndTime!.Value - a.StartTime).TotalMinutes)
                    .DefaultIfEmpty(0)
                    .Average(),
                AlertsByLevel = alerts.GroupBy(a => a.Level)
                    .ToDictionary(g => g.Key, g => g.Count()),
                AlertsByMetric = alerts.GroupBy(a => a.AlertRule.MetricName)
                    .ToDictionary(g => g.Key, g => g.Count())
            };
        }

        public async Task<SystemHealthStatus> GetSystemHealthStatusAsync()
        {
            var healthStatus = new SystemHealthStatus
            {
                LastCheckTime = DateTime.Now
            };

            // 检查数据库连接
            try
            {
                await _tenantRepository.CountAsync();
                healthStatus.ComponentStatus["database"] = HealthStatus.Healthy;
            }
            catch
            {
                healthStatus.ComponentStatus["database"] = HealthStatus.Unhealthy;
                healthStatus.Issues.Add("数据库连接失败");
            }

            // 检查活跃告警数量
            var activeAlerts = await _alertRepository.CountAsync(a => a.Status == AlertStatus.Active);
            healthStatus.Metrics["active_alerts"] = activeAlerts;

            if (activeAlerts > 10)
            {
                healthStatus.ComponentStatus["alerts"] = HealthStatus.Unhealthy;
            }
            else if (activeAlerts > 5)
            {
                healthStatus.ComponentStatus["alerts"] = HealthStatus.Warning;
            }
            else
            {
                healthStatus.ComponentStatus["alerts"] = HealthStatus.Healthy;
            }

            // 计算总体健康状态
            if (healthStatus.ComponentStatus.Values.Any(s => s == HealthStatus.Unhealthy))
            {
                healthStatus.OverallStatus = HealthStatus.Unhealthy;
            }
            else if (healthStatus.ComponentStatus.Values.Any(s => s == HealthStatus.Warning))
            {
                healthStatus.OverallStatus = HealthStatus.Warning;
            }
            else
            {
                healthStatus.OverallStatus = HealthStatus.Healthy;
            }

            return healthStatus;
        }

        private async Task CheckAlertRuleAsync(AlertRule rule)
        {
            try
            {
                var currentValue = await GetMetricValueAsync(rule.MetricName,
                    DateTime.Now.AddSeconds(-rule.Duration),
                    DateTime.Now,
                    rule.GetLabelFilters(),
                    rule.TenantId);

                if (currentValue.HasValue && rule.MatchesRule(currentValue.Value, rule.GetLabelFilters()))
                {
                    // 检查是否已经存在活跃的告警
                    var existingAlert = await _alertRepository.FirstOrDefaultAsync(a =>
                        a.AlertRuleId == rule.Id &&
                        a.Status == AlertStatus.Active);

                    if (existingAlert == null)
                    {
                        // 创建新的告警
                        rule.TriggerAlert(currentValue.Value, rule.GetLabelFilters());
                        await _alertRuleRepository.UpdateAsync(rule);

                        _logger.LogWarning("告警触发: {RuleName} - 当前值: {Value}, 阈值: {Threshold}",
                            rule.DisplayName, currentValue.Value, rule.Threshold);
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "检查告警规则失败: {RuleName}", rule.DisplayName);
            }
        }

        private async Task CheckAlertRulesForMetric(string metricName, decimal value, Dictionary<string, string>? dimensions, Guid? tenantId)
        {
            var rules = await _alertRuleRepository.GetListAsync(r =>
                r.IsEnabled &&
                r.MetricName == metricName &&
                r.TenantId == tenantId);

            foreach (var rule in rules)
            {
                if (rule.MatchesRule(value, dimensions))
                {
                    await CheckAlertRuleAsync(rule);
                }
            }
        }

        private MetricType GetMetricTypeFromName(string metricName)
        {
            if (metricName.Contains("count") || metricName.Contains("total"))
                return MetricType.Counter;
            if (metricName.Contains("percentage") || metricName.Contains("rate"))
                return MetricType.Gauge;
            if (metricName.Contains("time") || metricName.Contains("duration"))
                return MetricType.Histogram;
            return MetricType.Gauge;
        }

        private MetricCategory GetMetricCategoryFromName(string metricName)
        {
            if (metricName.StartsWith("tenant_"))
                return MetricCategory.Tenant;
            if (metricName.StartsWith("system_"))
                return MetricCategory.System;
            if (metricName.StartsWith("business_"))
                return MetricCategory.Business;
            if (metricName.Contains("performance") || metricName.Contains("response_time"))
                return MetricCategory.Performance;
            return MetricCategory.Tenant;
        }

        private MetricUnit GetMetricUnitFromName(string metricName)
        {
            if (metricName.Contains("percentage"))
                return MetricUnit.Percentage;
            if (metricName.Contains("bytes") || metricName.Contains("storage"))
                return MetricUnit.Bytes;
            if (metricName.Contains("time"))
                return MetricUnit.Milliseconds;
            if (metricName.Contains("rate"))
                return MetricUnit.RequestsPerSecond;
            if (metricName.Contains("count"))
                return MetricUnit.Count;
            return MetricUnit.None;
        }
    }
}